package com.webmuseum.client;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasHorizontalAlignment.HorizontalAlignmentConstant;
import com.google.gwt.user.client.ui.IntegerBox;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.LongBox;
import com.google.gwt.user.client.ui.StackPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.datepicker.client.DatePicker;
import com.google.gwt.xml.client.Document;
import com.google.gwt.xml.client.NamedNodeMap;
import com.google.gwt.xml.client.Node;
import com.google.gwt.xml.client.NodeList;
import com.google.gwt.xml.client.XMLParser;

public class CardFactory {

	private static CardFactory mInstance = null;
	//private HashMap<String, CardInfo> mCardMap;	// <cardName, xml>
	private List<CardPanel> mCardPanelList;
	
	private CardFactory(){ }
	
	public  static CardFactory getInstance()
	{
		if(mInstance == null)
		{
			mInstance = new CardFactory();
		}
		
		return mInstance;
	}
	
	public void init()
	{
		//Init the card panel list
		mCardPanelList = new ArrayList<CardPanel>();
		
		//Read card index
	    final String url = GWT.getHostPageBaseURL()+"cardIndex.xml";
	    RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(url));

	    try 
	    {
	      Request request = builder.sendRequest(null, new RequestCallback() 
	      {
	        public void onError(Request request, Throwable exception) 
	        {
	           // Couldn't connect to server (could be timeout, SOP violation, etc.)
	        	//Window.alert("Cant get "+url);
	        }

	        public void onResponseReceived(Request request, Response response) 
	        {
	          if (200 == response.getStatusCode()) {
	        	  //For each entry in the xml card index
	        	  //get the file from the server and pass to the cardFactory
	        	  //to create the relative prototype
	        	  Document xml = XMLParser.parse(response.getText());
	        	  NodeList cardList = xml.getElementsByTagName("Card");
	        	  for(int i=0; i < cardList.getLength(); ++i)
	        	  {
	        		  NamedNodeMap attList = cardList.item(i).getAttributes();
	        		  String xmlName  = attList.getNamedItem("xmlName").getNodeValue();
	        		  loadXmlCard(xmlName);
	        	  }
	        	  
	          } 
	          else 
	          {
	            // Handle the error.  Can get the status text from response.getStatusText()
	          }
	        }       
	      });
	    } 
	    catch (RequestException e) 
	    {
	    
	    }

	}
	
	public CardPanel getCardPanel(int aIndex)
	{
		return mCardPanelList.get(aIndex);
	}
	
	public void addCardPanel(CardPanel aCardPanel)
	{
		mCardPanelList.add(aCardPanel);		
	}
	
	public List<CardPanel> getCardPanelList()
	{
		return mCardPanelList;
	}
	
	private void loadXmlCard(String aXmlCardFile)
	{
		String url = GWT.getHostPageBaseURL() + aXmlCardFile;
		RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(url));
		try 
		{
			Request request = builder.sendRequest(null, new RequestCallback() 
			{
				public void onError(Request request, Throwable exception) 
				{
					// Couldn't connect to server (could be timeout, SOP violation, etc.)
					Window.alert("ERROR: Cannot read XML card file");
				}

				public void onResponseReceived(Request request, Response response) 
				{
					if (200 == response.getStatusCode()) 
					{
						//Window.alert(response.getText());

						//Xml file ready to parse
						CardPanel cardPanel = new CardPanel();
						Document xml = XMLParser.parse(response.getText());
						cardPanel.setTitle(xml.getDocumentElement().getAttributes().getNamedItem("alias").getNodeValue());

						//Create UI element on the base of xml nodes
						//Paragraph
						NodeList paraList = xml.getElementsByTagName("Paragraph");
						Window.alert(xml.toString());
						for(int i= 0; i < paraList.getLength(); ++i)
						{
							Node paraNode = paraList.item(i);
							NamedNodeMap paraAttributes = paraNode.getAttributes();
							
							if(paraAttributes.getNamedItem("visible").getNodeValue().equals("true"))
							{
								//ContainerPanel paraPanel = new ContainerPanel();
								
								//Create Title
								//Label paraLabel = new Label();
								//paraLabel.setStylePrimaryName("paragraph-title");
								//paraLabel.setText(paraAttributes.getNamedItem("alias").getNodeValue());
								//paraLabel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
								//paraPanel.add(paraLabel);
								
								DisclosurePanel discPanel = new DisclosurePanel(paraAttributes.getNamedItem("alias").getNodeValue());
								discPanel.setTitle(paraAttributes.getNamedItem("name").getNodeValue());
								discPanel.setAnimationEnabled(true);
								
								//Create Content
								ParagraphContent paraContent = new ParagraphContent();
								//paraContent.setHeader(paraLabel);
								//paraContent.add(paraLabel);
								
								//Create FieldData
								CommonFieldData cData = new CommonFieldData();
								cData.setMinOccur( (paraAttributes.getNamedItem("minOccurs").getNodeValue().equals("1") ? true: false));
								cData.setMaxOccur( (paraAttributes.getNamedItem("maxOccurs").getNodeValue().equals("1") ?
															CommonFieldData.msMaxOccurEnum.OCCUR_ONE : 
															CommonFieldData.msMaxOccurEnum.OCCUR_UNBOUND));
								FieldManager.getInstance().addFieldData(paraAttributes.getNamedItem("name").getNodeValue(), cData);
								
								//Handle the contents of the paragraphs
								NodeList paraChildren = paraNode.getChildNodes();
								for(int k=0; k < paraChildren.getLength(); ++k)
								{
									Node paraChild = paraChildren.item(k);
									if(paraChild.getNodeName().equals("SimpleField"))
									{
										NamedNodeMap childAttributes = paraChild.getAttributes();
										if(childAttributes.getNamedItem("visible").getNodeValue().equals("true"))
										{	
											Widget widget = getWidget(childAttributes, childAttributes.getNamedItem("type").getNodeValue());
											if(widget != null)
											{
												DisclosurePanel discSimple = new DisclosurePanel(childAttributes.getNamedItem("alias").getNodeValue());
												discSimple.setTitle(childAttributes.getNamedItem("name").getNodeValue());
												discSimple.setAnimationEnabled(true);
												
												//Create Content
												SimpleFieldContent simpleContent = new SimpleFieldContent();
												
												//Create FieldData
												FieldData fData = new FieldData();
												fData.setMinOccur( (childAttributes.getNamedItem("minOccurs").getNodeValue().equals("1") ? true: false));
												fData.setMaxOccur( (childAttributes.getNamedItem("maxOccurs").getNodeValue().equals("1") ?
																			CommonFieldData.msMaxOccurEnum.OCCUR_ONE : 
																			CommonFieldData.msMaxOccurEnum.OCCUR_UNBOUND));
												//Window.alert("Field name "+discSimple.getTitle() +", Tab name "+s);
												fData.setTableName(StringManager.getInstance().addString(childAttributes.getNamedItem("table").getNodeValue()));
												
												if(childAttributes.getNamedItem("vocabulary") != null)
												{
													fData.setVocabularyType( (childAttributes.getNamedItem("vocabulary").getNodeValue().equals("open") ?
																					FieldData.msVocTypeEnum.TYPE_OPEN :
																					FieldData.msVocTypeEnum.TYPE_CLOSED) );
												}
												
												FieldManager.getInstance().addFieldData(childAttributes.getNamedItem("name").getNodeValue(), fData);
												
												//Window.alert("fData: "+discSimple.getTitle()+", "+fData.getTableName());
												
												/*
												Label childLabel = new Label();
												childLabel.setStylePrimaryName("simpleField-title");
												childLabel.setText(childAttributes.getNamedItem("alias").getNodeValue());
												childLabel.setTitle(childAttributes.getNamedItem("name").getNodeValue());
												simpleContent.add(childLabel);
												*/
												
												simpleContent.add(widget);
												discSimple.setContent(simpleContent);
												//Duplicatable or not?
												if(childAttributes.getNamedItem("maxOccurs").getNodeValue().equals("unbounded"))
												{
													UIMultiContainer simpleTable = new UIMultiContainer(discSimple);
													//paraPanel.add(paraTable);
													paraContent.add(simpleTable);
												}
												else
												{
													UIContainer simple = new UIContainer(discSimple);
													//para.add(paraLabel);
													//paraPanel.add(para);
													paraContent.add(simple);
												}

											}
											
											
										}
									}
									else if(paraChild.getNodeName().equals("StructuredField"))
									{
										//Create a subPanel
										NamedNodeMap childAttributes = paraChild.getAttributes();
										if(childAttributes.getNamedItem("visible").getNodeValue().equals("true"))
										{	
											DisclosurePanel discStructPanel = new DisclosurePanel(childAttributes.getNamedItem("alias").getNodeValue());
											discStructPanel.setTitle(childAttributes.getNamedItem("name").getNodeValue());
											discStructPanel.setAnimationEnabled(true);
											
											//Create Content
											StructuredFieldContent structContent = new StructuredFieldContent(); 
											/*
											Label childLabel = new Label();
											childLabel.setStylePrimaryName("structuredField-title");
											childLabel.setText(childAttributes.getNamedItem("alias").getNodeValue());
											childLabel.setTitle(childAttributes.getNamedItem("name").getNodeValue());
											structContent.add(childLabel);
											 */
											
											//Create FieldData
											CommonFieldData scData = new CommonFieldData();
											scData.setMinOccur( (childAttributes.getNamedItem("minOccurs").getNodeValue().equals("1") ? true: false));
											scData.setMaxOccur( (childAttributes.getNamedItem("maxOccurs").getNodeValue().equals("1") ?
																		CommonFieldData.msMaxOccurEnum.OCCUR_ONE : 
																		CommonFieldData.msMaxOccurEnum.OCCUR_UNBOUND));
											
											FieldManager.getInstance().addFieldData(childAttributes.getNamedItem("name").getNodeValue(), scData);
											
											//Check SubFields
											NodeList structChildren = paraChild.getChildNodes();
											for(int j =0; j < structChildren.getLength();++j)
											{
												Node structChild = structChildren.item(j);
		
												if(structChild.getNodeName().equals("SubField"))
												{
													NamedNodeMap structChildAttributes = structChild.getAttributes();
													if(structChildAttributes.getNamedItem("visible").getNodeValue().equals("true"))
													{	
														Widget widget = getWidget(structChildAttributes, structChildAttributes.getNamedItem("type").getNodeValue());
														if(widget != null)
														{
															DisclosurePanel discSub = new DisclosurePanel(structChildAttributes.getNamedItem("alias").getNodeValue());
															discSub.setTitle(structChildAttributes.getNamedItem("name").getNodeValue());
															discSub.setAnimationEnabled(true);
															
															//Create Content
															SubFieldContent subContent = new SubFieldContent();
															/*
															Label subLabel = new Label();
															subLabel.setStylePrimaryName("subField-title");
															subLabel.setText(structChildAttributes.getNamedItem("alias").getNodeValue());
															subLabel.setTitle(structChildAttributes.getNamedItem("name").getNodeValue());
															subContent.add(subLabel);
															*/
															
															//Create FieldData
															FieldData subfData = new FieldData();
															subfData.setMinOccur( (structChildAttributes.getNamedItem("minOccurs").getNodeValue().equals("1") ? true: false));
															subfData.setMaxOccur( (structChildAttributes.getNamedItem("maxOccurs").getNodeValue().equals("1") ?
																						CommonFieldData.msMaxOccurEnum.OCCUR_ONE : 
																						CommonFieldData.msMaxOccurEnum.OCCUR_UNBOUND));
															subfData.setTableName(StringManager.getInstance().addString(structChildAttributes.getNamedItem("table").getNodeValue()));
															if(structChildAttributes.getNamedItem("vocabulary") != null)
															{
																subfData.setVocabularyType( (structChildAttributes.getNamedItem("vocabulary").getNodeValue().equals("open") ?
																								FieldData.msVocTypeEnum.TYPE_OPEN :
																								FieldData.msVocTypeEnum.TYPE_CLOSED) );
															}
															
															FieldManager.getInstance().addFieldData(structChildAttributes.getNamedItem("name").getNodeValue(), subfData);
															
															subContent.add(widget);
															discSub.setContent(subContent);
															
															//Duplicatable or not?
															if(childAttributes.getNamedItem("maxOccurs").getNodeValue().equals("unbounded"))
															{
																UIMultiContainer simpleTable = new UIMultiContainer(discSub);
																//paraPanel.add(paraTable);
																structContent.add(simpleTable);
															}
															else
															{
																UIContainer simple = new UIContainer(discSub);
																//para.add(paraLabel);
																//paraPanel.add(para);
																structContent.add(simple);
															}
														}
													}
												}
												
											}
											
											discStructPanel.setContent(structContent);
											//Duplicatable or not?
											if(childAttributes.getNamedItem("maxOccurs").getNodeValue().equals("unbounded"))
											{
												UIMultiContainer simpleTable = new UIMultiContainer(discStructPanel);
												//paraPanel.add(paraTable);
												paraContent.add(simpleTable);
											}
											else
											{
												UIContainer simple = new UIContainer(discStructPanel);
												//para.add(paraLabel);
												//paraPanel.add(para);
												paraContent.add(simple);
											}

										}
									}
								}
								
								discPanel.setContent(paraContent);
								
								//Check what kind of paragraph is this to handle duplication
								if(paraAttributes.getNamedItem("maxOccurs").getNodeValue().equals("unbounded"))
								{
									UIMultiContainer paraTable = new UIMultiContainer(discPanel);
									//paraPanel.add(paraTable);
									cardPanel.add(paraTable);
								}
								else
								{
									UIContainer para = new UIContainer(discPanel);
									//para.add(paraLabel);
									//paraPanel.add(para);
									cardPanel.add(para);
								}
							}
							
						}
						//Add panel to panel list
						addCardPanel(cardPanel);

					} else {
						// Handle the error.  Can get the status text from response.getStatusText()
					}
				}       
			});
		} 
		catch (RequestException e) 
		{

		}
	}

	protected Widget getWidget(NamedNodeMap aNodeAttributes, String aNodeType) 
	{
		Widget widget = null;
		
		if(aNodeType.equals("text"))
		{
			TextBox structChildBox = new TextBox();
			structChildBox.setMaxLength(Integer.valueOf(aNodeAttributes.getNamedItem("maxLength").getNodeValue()));
			widget = structChildBox;
		}
		else if(aNodeType.equals("date"))
		{
			widget = new DatePicker();
		}
		else if(aNodeType.equals("numcode"))
		{
			IntegerBox box = new IntegerBox();
			box.setMaxLength(Integer.valueOf(aNodeAttributes.getNamedItem("maxLength").getNodeValue()));
			widget = box;
		}
		else if(aNodeType.equals("long"))
		{
			LongBox box = new LongBox();
			box.setMaxLength(Integer.valueOf(aNodeAttributes.getNamedItem("maxLength").getNodeValue()));
			widget = box;
		}
		
		return widget;
	}
	
    
    //Test servlet
    /*
    webService.getCardInfo( new AsyncCallback<List<CardInfo>>() 
    		{
				public void onFailure(Throwable caught) 
				{
					Window.alert("NADA");
				}

				public void onSuccess(List<CardInfo> result) 
				{
					for(int i=0; i < result.size(); ++i)
					{
						//mContentPanel.add(new Label(result.get(i)) );
					}
				}
    		});
   */
	
}
